﻿#pragma once

#include <xy/utils/json.h>
#include <xy/utils/reflect_trait.h>

namespace xy
{

namespace utils
{

template <typename T>
concept is_convertible_from_json = requires { std::declval<json>().as<T>(); };

template <typename T>
concept is_serializable = requires(T t) {
    serialize(t);
    deserialize(std::declval<json>(), t);
};

struct serialize_trait
{
    /**
     * @brief 不支持序列化的类型，抛出异常
     *
     * @tparam T
     * @return json
     */
    template <class T> static auto serialize(const T &) -> json
    {
        throw std::runtime_error("No serialization support for this type.");
        return json{};
    }

    /**
     * @brief 外部序列化实现
     *
     * @tparam T
     */
    template <class T>
        requires(is_serializable<T>)
    static auto serialize(const T &obj) -> json
    {
        // 注意调用外部函数，防止无限递归
        return ::serialize(obj);
    }

    /**
     * @brief 无序列化实现，但可直接转换为 json（Json 可通过其初始化）
     *
     * @tparam T
     */
    template <class T>
        requires(!details::reflect_trait_impl<T>::has_members() && std::is_convertible_v<T, json>)
    static auto serialize(const T &obj) -> json
    {
        return obj;
    }

    /**
     * @brief 序列化类成员变量
     *
     * @tparam T
     */
    template <class T>
        requires(details::reflect_trait_impl<T>::has_members())
    static auto serialize(const T &obj) -> json
    {
        json data;
        reflect_trait::for_each_member_variable(
            obj, [&data](const auto &key, const auto &value) { data[key] = serialize(value); });
        return data;
    }

    /**
     * @brief 不支持反序列化的类型，抛出异常
     *
     * @tparam T
     */
    template <class T> static void deserialize(const json &, T &)
    {
        throw std::runtime_error("No serialization support for this type.");
    }

    /**
     * @brief 外部反序列化实现
     *
     * @tparam T
     */
    template <class T>
        requires(is_serializable<T>)
    static void deserialize(const json &data, T &obj)
    {
        // 注意调用外部函数，防止无限递归
        ::deserialize(data, obj);
    }

    /**
     * @brief 无反序列化实现，但可直接赋值（Json.as 可转换）
     *
     * @tparam T
     */
    template <class T>
        requires(!details::reflect_trait_impl<T>::has_members() && is_convertible_from_json<std::decay_t<T>>)
    static void deserialize(const json &data, T &obj)
    {
        using Ty = std::decay_t<T>;
        const_cast<Ty &>(obj) = data.as<Ty>();
    }

    /**
     * @brief 反序列化类成员变量
     *
     * @tparam T
     */
    template <class T>
        requires(details::reflect_trait_impl<T>::has_members())
    static void deserialize(const json &data, T &obj)
    {
        reflect_trait::for_each_member_variable(
            obj, [&data](const auto &key, auto &value) { deserialize(data[key], value); });
    }
};

} // namespace utils

} // namespace xy
